package com.blacktech.dbu.auth.service;

import com.blacktech.dbu.auth.dto.LoginRequest;
import com.blacktech.dbu.auth.dto.LoginResponse;
import com.blacktech.dbu.auth.entity.DbuUser;
import com.blacktech.dbu.core.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 认证服务
 *
 * @author Yanyunsong
 */
@Service
@Transactional
public class AuthenticationService {

    private static final Logger logger = LoggerFactory.getLogger(AuthenticationService.class);

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private AuthorizationService authorizationService;

    @Autowired
    private UserService userService;

    @Autowired
    private JwtUtil jwtUtil;

    @Value("${app.jwt.expiration:7200}")
    private int jwtExpiration;

    /**
     * 用户登录
     */
    public LoginResponse login(LoginRequest request, String ipAddress, String userAgent) {
        try {
            // 进行认证
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            request.getUsername(),
                            request.getPassword()
                    )
            );

            SecurityContextHolder.getContext().setAuthentication(authentication);

            // 获取用户信息
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            DbuUser user = userService.getUserByUsername(userDetails.getUsername())
                    .orElseThrow(() -> new BadCredentialsException("用户不存在"));

            // 检查账户状态
            if (!user.isEnabled()) {
                throw new BadCredentialsException("账户已禁用");
            }

            if (!user.isAccountNonLocked()) {
                // 检查锁定是否已过期
                if (user.isLockExpired()) {
                    userService.unlockUser(user.getId(), null);
                } else {
                    throw new BadCredentialsException("账户已锁定，请稍后再试");
                }
            }

            // 生成JWT令牌
            String accessToken = jwtUtil.generateAccessToken(
                    user.getUsername(),
                    user.getId(),
                    user.getUserType().name()
            );

            String refreshToken = jwtUtil.generateRefreshToken(
                    user.getUsername(),
                    user.getId()
            );

            // 更新最后登录时间
            userService.updateLastLoginTime(user.getId());

            // 重置登录失败次数
            userService.resetLoginFailedCount(user.getId());

            // 记录登录日志
            logLoginOperation(user.getId(), "LOGIN", "用户登录", ipAddress, userAgent, null);

            // 构建响应
            LoginResponse response = new LoginResponse();
            response.setAccessToken(accessToken);
            response.setRefreshToken(refreshToken);
            response.setExpiresIn((long) jwtExpiration);

            LoginResponse.UserInfo userInfo = new LoginResponse.UserInfo();
            userInfo.setId(user.getId());
            userInfo.setUsername(user.getUsername());
            userInfo.setDisplayName(user.getDisplayName());
            userInfo.setEmail(user.getEmail());
            userInfo.setUserType(user.getUserType().name());
            userInfo.setStatus(user.getStatus().name());
            userInfo.setLastLoginTime(user.getLastLoginTime());

            response.setUserInfo(userInfo);

            logger.info("用户登录成功: {}", user.getUsername());
            return response;

        } catch (AuthenticationException e) {
            // 登录失败，增加失败次数
            userService.increaseLoginFailedCount(request.getUsername());

            // 记录登录失败日志
            logLoginOperation(null, "LOGIN_FAILED", "登录失败: " + e.getMessage(), ipAddress, userAgent, e.getMessage());

            logger.warn("用户登录失败: {} - {}", request.getUsername(), e.getMessage());
            throw new BadCredentialsException("用户名或密码错误");
        }
    }

    /**
     * 用户登出
     */
    public void logout(String ipAddress, String userAgent) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            DbuUser user = userService.getUserByUsername(userDetails.getUsername())
                    .orElse(null);

            if (user != null) {
                // 记录登出日志
                logLoginOperation(user.getId(), "LOGOUT", "用户登出", ipAddress, userAgent, null);
                logger.info("用户登出成功: {}", user.getUsername());
            }
        }

        // 清除认证上下文
        SecurityContextHolder.clearContext();
    }

    /**
     * 刷新访问令牌
     */
    public LoginResponse refreshToken(String refreshToken, String ipAddress) {
        try {
            // 验证刷新令牌
            if (!jwtUtil.isRefreshToken(refreshToken)) {
                throw new BadCredentialsException("无效的刷新令牌");
            }

            if (jwtUtil.isTokenExpired(refreshToken)) {
                throw new BadCredentialsException("刷新令牌已过期");
            }

            // 生成新的访问令牌
            String username = jwtUtil.getUsernameFromToken(refreshToken);
            Long userId = jwtUtil.getUserIdFromToken(refreshToken);
            String userType = jwtUtil.getUserTypeFromToken(refreshToken);

            String newAccessToken = jwtUtil.generateAccessToken(username, userId, userType);
            String newRefreshToken = jwtUtil.generateRefreshToken(username, userId);

            // 记录令牌刷新日志
            if (userId != null) {
                logLoginOperation(userId, "REFRESH_TOKEN", "刷新访问令牌", ipAddress, null, null);
            }

            // 构建响应
            LoginResponse response = new LoginResponse();
            response.setAccessToken(newAccessToken);
            response.setRefreshToken(newRefreshToken);
            response.setExpiresIn((long) jwtExpiration);

            logger.info("访问令牌刷新成功: {}", username);
            return response;

        } catch (Exception e) {
            logger.warn("访问令牌刷新失败: {}", e.getMessage());
            throw new BadCredentialsException("令牌刷新失败: " + e.getMessage());
        }
    }

    /**
     * 获取当前登录用户
     */
    @Transactional(readOnly = true)
    public DbuUser getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            return userService.getUserByUsername(userDetails.getUsername()).orElse(null);
        }
        return null;
    }

    /**
     * 获取当前登录用户ID
     */
    @Transactional(readOnly = true)
    public Long getCurrentUserId() {
        DbuUser currentUser = getCurrentUser();
        return currentUser != null ? currentUser.getId() : null;
    }

    /**
     * 记录登录相关操作日志
     */
    private void logLoginOperation(Long userId, String operationType, String operationDesc,
                                  String ipAddress, String userAgent, String errorMessage) {
        // 这里需要注入OperationLogService来记录日志
        // 为了避免循环依赖，可以考虑使用AOP或事件机制
        logger.info("记录操作日志: userId={}, operation={}, ip={}, error={}",
                userId, operationType, ipAddress, errorMessage);
    }
}